load("@rules_rust//cargo:defs.bzl", "cargo_build_script")
load("@rules_rust//rust:defs.bzl", "rust_library", "rust_test")
load("//bazel:canbench.bzl", "rust_canbench")
load("//bazel:canisters.bzl", "rust_canister")
load("//bazel:defs.bzl", "rust_test_suite_with_extra_srcs")
load("//bazel:prost.bzl", "generated_files_check")
load("//rs/nervous_system/patch_canister_did:defs.bzl", "canister_test_did")

package(default_visibility = ["//visibility:public"])

filegroup(
    name = "protos",
    srcs = glob(["proto/**/*.proto"]),
)

exports_files(
    [
        "canister/governance.did",
        "canister/governance_test.did.patch",
    ],
    visibility = [
        "//visibility:public",
    ],
)

canister_test_did(
    name = "test_did",
    canister_did = "canister/governance.did",
    canister_test_did_patch = "canister/governance_test.did.patch",
    output_path = "canister/governance_test.did",
)

DEPENDENCIES = [
    # Keep sorted.
    "//packages/ic-http-types",
    "//packages/icrc-ledger-client:icrc_ledger_client",
    "//packages/icrc-ledger-types:icrc_ledger_types",
    "//rs/crypto/sha2",
    "//rs/ledger_suite/common/ledger_core",
    "//rs/ledger_suite/icp:icp_ledger",
    "//rs/ledger_suite/icrc1/ledger",
    "//rs/nervous_system/candid_utils",
    "//rs/nervous_system/canisters",
    "//rs/nervous_system/clients",
    "//rs/nervous_system/collections/union_multi_map",
    "//rs/nervous_system/common",
    "//rs/nervous_system/common/validation",
    "//rs/nervous_system/governance",
    "//rs/nervous_system/linear_map",
    "//rs/nervous_system/lock",
    "//rs/nervous_system/proto",
    "//rs/nervous_system/root",
    "//rs/nervous_system/runtime",
    "//rs/nervous_system/temporary",
    "//rs/nervous_system/timestamp",
    "//rs/nns/constants",
    "//rs/protobuf",
    "//rs/rust_canisters/canister_log",
    "//rs/rust_canisters/canister_profiler",
    "//rs/sns/governance/api",
    "//rs/sns/governance/proposal_criticality",
    "//rs/sns/governance/proposals_amount_total_limit",
    "//rs/sns/governance/token_valuation",
    "//rs/sns/treasury_manager",
    "//rs/types/base_types",
    "//rs/types/management_canister_types",
    "//rs/utils",
    "@crate_index//:base64",
    "@crate_index//:build-info",
    "@crate_index//:candid",
    "@crate_index//:clap",
    "@crate_index//:comparable",
    "@crate_index//:futures",
    "@crate_index//:hex",
    "@crate_index//:ic-cdk",
    "@crate_index//:ic-cdk-timers",
    "@crate_index//:ic-metrics-encoder",
    "@crate_index//:ic-stable-structures",
    "@crate_index//:itertools",
    "@crate_index//:lazy_static",
    "@crate_index//:maplit",
    "@crate_index//:num-traits",
    "@crate_index//:prost",
    "@crate_index//:rand",
    "@crate_index//:rand_chacha",
    "@crate_index//:rust_decimal",
    "@crate_index//:serde",
    "@crate_index//:serde_bytes",
    "@crate_index//:serde_json",
    "@crate_index//:strum",
    "@crate_index//:thiserror",
]

MACRO_DEPENDENCIES = [
    # Keep sorted.
    "//rs/nervous_system/common/build_metadata",
    "@crate_index//:async-trait",
    "@crate_index//:rust_decimal_macros",
    "@crate_index//:strum_macros",
]

BUILD_DEPENDENCIES = [
    # Keep sorted.
    "//rs/types/base_types",
    "@crate_index//:build-info-build",
    "@crate_index//:prost-build",
]

DEV_DEPENDENCIES = [
    # Keep sorted.
    "//rs/canister_client/sender",
    "//rs/nervous_system/common/test_keys",
    "//rs/nervous_system/common/test_utils",
    "//rs/sns/governance/protobuf_generator:lib",
    "//rs/sns/test_utils",
    "//rs/test_utilities/compare_dirs",
    "//rs/test_utilities/types",
    "@crate_index//:assert_matches",
    "@crate_index//:candid_parser",
    "@crate_index//:pretty_assertions",
    "@crate_index//:proptest",
    "@crate_index//:tempfile",
    "@crate_index//:tokio",
    "@crate_index//:tokio-test",
]

MACRO_DEV_DEPENDENCIES = []

ALIASES = {}

LIB_SRCS = glob(
    ["src/**"],
    # Ensures that we do not need to rebuild just because a _test.rs file
    # changed.
    exclude = ["**/*tests.rs"],
)

cargo_build_script(
    name = "build_script",
    srcs = ["build.rs"],
    aliases = ALIASES,
    data = [],  # build script data (e.g. template files) goes here
    version = "0.9.0",
    deps = BUILD_DEPENDENCIES,
)

rust_library(
    name = "governance",
    srcs = LIB_SRCS,
    aliases = ALIASES,
    crate_name = "ic_sns_governance",
    proc_macro_deps = MACRO_DEPENDENCIES,
    version = "0.9.0",
    deps = DEPENDENCIES + [":build_script"],
)

rust_library(
    name = "governance--test_feature",
    srcs = LIB_SRCS,
    aliases = ALIASES,
    crate_features = ["test"],
    crate_name = "ic_sns_governance",
    proc_macro_deps = MACRO_DEPENDENCIES,
    version = "0.9.0",
    deps = DEPENDENCIES + [":build_script"],
)

rust_library(
    name = "governance--canbench_feature",
    srcs = LIB_SRCS,
    aliases = ALIASES,
    crate_features = ["canbench-rs"],
    crate_name = "ic_sns_governance",
    proc_macro_deps = MACRO_DEPENDENCIES,
    version = "0.9.0",
    deps = DEPENDENCIES + [
        ":build_script",
        "@crate_index//:canbench-rs",
    ],
)

rust_canister(
    name = "sns-governance-canister",
    srcs = ["canister/canister.rs"],
    aliases = ALIASES,
    compile_data = [":canister/governance.did"],
    proc_macro_deps = MACRO_DEPENDENCIES,
    service_file = ":canister/governance.did",
    deps = DEPENDENCIES + [
        ":build_script",
        ":governance",
    ],
)

rust_canister(
    name = "sns-governance-canister-test",
    testonly = True,
    srcs = ["canister/canister.rs"],
    aliases = ALIASES,
    compile_data = [":test_did"],
    crate_features = ["test"],
    did_check = False,  # we don't check in the did so can't meaningfully check
    proc_macro_deps = MACRO_DEPENDENCIES,
    service_file = ":test_did",
    deps = DEPENDENCIES + [
        ":build_script",
        ":governance--test_feature",
    ],
)

rust_test(
    name = "governance_test",
    srcs = glob(["src/**/*.rs"]),
    aliases = ALIASES,
    proc_macro_deps = MACRO_DEPENDENCIES + MACRO_DEV_DEPENDENCIES,
    deps = [":governance"] + DEPENDENCIES + DEV_DEPENDENCIES + [":build_script"],
)

rust_test(
    name = "governance_test--test-feature",
    srcs = glob(["src/**/*.rs"]),
    aliases = ALIASES,
    crate_features = ["test"],
    proc_macro_deps = MACRO_DEPENDENCIES + MACRO_DEV_DEPENDENCIES,
    deps = [":governance"] + DEPENDENCIES + DEV_DEPENDENCIES + [":build_script"],
)

rust_test(
    name = "canister_unit_test",
    srcs = glob(["canister/**/*.rs"]),
    compile_data = [":canister/governance.did"],
    crate_root = "canister/canister.rs",
    proc_macro_deps = MACRO_DEPENDENCIES,
    deps = DEPENDENCIES + DEV_DEPENDENCIES + [
        ":build_script",
        ":governance",
    ],
)

rust_test(
    name = "canister_test_unit_test",
    srcs = glob(["canister/**/*.rs"]),
    compile_data = [":test_did"],
    crate_features = ["test"],
    crate_root = "canister/canister.rs",
    proc_macro_deps = MACRO_DEPENDENCIES + MACRO_DEV_DEPENDENCIES,
    deps = DEPENDENCIES + DEV_DEPENDENCIES + [
        ":build_script",
        ":governance--test_feature",
    ],
)

rust_test_suite_with_extra_srcs(
    name = "governance_integration",
    srcs = glob(
        ["tests/**/*.rs"],
        exclude = [
            "tests/check_generated_files.rs",
            "tests/fixtures/mod.rs",
            "tests/fixtures/environment_fixture.rs",
        ],
    ),
    aliases = ALIASES,
    extra_srcs = [
        "tests/fixtures/mod.rs",
        "tests/fixtures/environment_fixture.rs",
    ],
    proc_macro_deps = MACRO_DEPENDENCIES + MACRO_DEV_DEPENDENCIES,
    deps = [":governance"] + DEPENDENCIES + DEV_DEPENDENCIES + [":build_script"],
)

generated_files_check(
    name = "check_generated_files",
    srcs = ["tests/check_generated_files.rs"],
    data = glob(["src/gen/**"]) + [
        ":protos",
        "//rs/ledger_suite/icp:protos",
        "//rs/nervous_system/proto:protos",
        "//rs/protobuf:protos",
        "//rs/types/base_types:protos",
    ],
    manifest_dir = "rs/sns/governance",
    deps = [
        # Keep sorted.
        "//rs/sns/governance/protobuf_generator:lib",
        "//rs/test_utilities/compare_dirs",
        "@crate_index//:tempfile",
    ],
)

# Usage
# =====
#
# For benchmarking (see `canbench/canbench_results.yml`):
# ```
# bazel run //rs/sns/governance:governance-canbench
# ```
#
# For updating the results file:
# ```
# bazel run //rs/sns/governance:governance-canbench_update
# ```
#
# To run the test:
# ```
# bazel test //rs/sns/governance:governance_canbench_test
# ```
#
# Currently, updating the results file is not automated, and there are no tests to avoid
# regression. For now, we can use it as an example for benchmarking as part
# of an investigation of potential performance issues, or when we make a change that can affect
# the performance measured in this benchmark.
rust_canbench(
    name = "governance-canbench",
    srcs = ["canbench/main.rs"],
    add_test = True,
    opt = "s",
    results_file = "canbench/canbench_results.yml",
    deps = [
        # Keep sorted.
        ":governance--canbench_feature",
    ],
)
